package models;

import global.ConfigData;

import java.io.IOException;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import lib.Field;
import lib.persistence.ExcelConnector;
import lib.persistence.NotFoundException;
import lib.persistence.commands.GetRow;
import lib.reflection.Reflector;
import models.Deliverable;
import models.Person;
import models.Milestone.Status;

public class Milestone extends ModelAbstract
{
	public enum Status {Incomplete, Complete};

	private Date creationDate;
	private Person creator; 
	private Project project;
	private String title;
	private int milestoneNumber;
	private Date projectedCompletion;
	private Date completionDate;
	private Status status;
	private ArrayList<Deliverable> deliverables = new ArrayList<Deliverable>();
	private String additionalNotes;
	private final static String WORKSHEET_NAME = "Milestone"; 


	// CTORS

	public Milestone(int id, Date creationDate,
			Person creator, String title, int milestoneNumber,
			Date projectedCompletion, Date completionDate, Status status,
			ArrayList<Deliverable> deliverables, String aditionalNotes) {
		super();
		this.id = id;
		this.creationDate = creationDate;
		this.creator = creator;
		this.title = title;
		this.milestoneNumber = milestoneNumber;
		this.projectedCompletion = projectedCompletion;
		this.completionDate = completionDate;
		this.status = status;
		this.deliverables = deliverables;
		this.additionalNotes = aditionalNotes;
	}

	public void setMilestoneNumber(int milestoneNumber) {
		this.milestoneNumber = milestoneNumber;
	}
	
	// END CTORS

	public Milestone() {
		// TODO Auto-generated constructor stub
	}

	// Setters and getters 
	
	public Date getCreationDate() {
		return creationDate;
	}
	public void setCreationDate(Date creationDate) {
		this.creationDate = creationDate;
	}
	public Person getCreator() {
		return creator;
	}
	public void setCreator(Person creator) {
		this.creator = creator;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public int getMilestoneNumber() {

		return milestoneNumber;
	}

	public Date getProjectedCompletion() {
		return projectedCompletion;
	}
	public void setProjectedCompletion(Date projectedCompletion) {
		this.projectedCompletion = projectedCompletion;
	}
	public Date getCompletionDate() {
		return completionDate;
	}
	public void setCompletionDate(Date completionDate) {
		this.completionDate = completionDate;
	}
	public Status getStatus() {
		return status;
	}
	public void setStatus(Status status) {
		this.status = status;
	}
	public void setStatus(String status) {
		this.status = Status.valueOf(status);
	}
	public ArrayList<Deliverable> getDeliverables() {
		return deliverables;
	}
	public void setDeliverables(ArrayList<Deliverable> deliverables) {
		this.deliverables = deliverables;
	}
	public String getAditionalNotes() {
	    return getAdditionalNotes();
	}

	public String getAdditionalNotes() {
		return additionalNotes;
	}
	public void setAditionalNotes(String aditionalNotes) {
	    setAdditionalNotes(aditionalNotes);
	}

	public void setAdditionalNotes(String aditionalNotes) {
		this.additionalNotes = aditionalNotes;
	}

	public int getNumberDeliverables()
	{
		int i = 0;
		Iterator<Deliverable> iterator = deliverables.iterator();
		while(iterator.hasNext())
		{
			i++;
			iterator.next();
		}

		return i;
	}

	public void addDeliverable(Deliverable deliverable)
	{
		deliverables.add(deliverable);
	}
	
	// subject to change and or cleanup
	private void setProject(Project project) {
		this.project = project;
	}

	private Project getProject() {
		return project;
	}
	
	// End setters and getters

	public boolean equals(Milestone o)
	{
		if (o == null)
			return false;
		if (!this.additionalNotes.equalsIgnoreCase(o.additionalNotes))
			return false;
		if (!this.completionDate.equals(o.completionDate))
			return false;
		if (!this.creationDate.equals(o.creationDate))
			return false;
		if (this.creator != null)
		{
			if (!this.creator.equals(o.creator))
				return false;			
		}
		if (this.project != null)
		{
			if (!this.project.equals(o.project))
				return false;			
		}
		if (this.id != o.id)
			return false;
		if (this.milestoneNumber != o.milestoneNumber)
			return false;
		if (!this.projectedCompletion.equals(o.projectedCompletion))
			return false;
		if (this.status != o.status)
			return false;
		if (!this.title.equalsIgnoreCase(o.title))
			return false;

		if (this.deliverables != null && o.deliverables !=null)
		{

			Iterator<Deliverable> thisIterator, oIterator;
			thisIterator = this.deliverables.iterator();
			oIterator = o.deliverables.iterator();

			while (thisIterator.hasNext() && oIterator.hasNext())
			{
				if (!thisIterator.next().equals(oIterator.next()))
					return false;
			}

			if (thisIterator.hasNext() || oIterator.hasNext())
				return false;
		}
		else
			if (this.deliverables != null || o.deliverables != null)
				return false;

		return true;
	}

	@Override
	public int getId() {
		return id;
	}

	@Override
	protected ArrayList<Field> getSqlReadyFields() {
		ArrayList<Field> al = new ArrayList<Field>();
		Field f;
		
		// add blob
		f = new Field();
		al.add(f.setName("obj").setType("blob").setObjValue(this));
		f = new Field();
		// add title
		al.add(f.setName("title").setType("string").setValue(this.getTitle()));

		// add milestone #
		f = new Field();
		al.add(f.setName("milestoneNumber").setType("integer").setValue("" +this.milestoneNumber));
		// add projectedCompletionDate
		f = new Field();
		al.add(f.setName("dateprojected").setType("date").setObjValue(this.projectedCompletion));
		// date achieved
		f = new Field();
		al.add(f.setName("dateachieved").setType("date").setObjValue(this.completionDate));
		// status
		f = new Field();
		al.add(f.setName("status").setType("string").setValue(this.status.toString()));

		//add creator
		if (creator != null)
		{		
			f = new Field();
			al.add(f.setName("createdBy").setType("integer").setValue("" + creator.getId()));
		}

		String deliverableIds = "";
		for (int i = 0 ; i < deliverables.size() ; i++)
		{
			deliverableIds = deliverableIds.concat(""+deliverables.get(i).getId());
			if (i < deliverables.size() - 1)
				deliverableIds = deliverableIds.concat(",");
		}
	    f = new Field();
	    al.add(f.setName("deliverable_ids").setType("string").setValue(deliverableIds));
		
		
		return al;
	}
	
	// Find milestone by the ID
	public static Milestone find(int id) throws NotFoundException, IOException, ClassNotFoundException, SQLException   
	{
		GetRow gr = new GetRow();
		Milestone m = (Milestone) gr.findObjectById(id, ConfigData.MILESTONE_TABLE, "obj");
		
		int createdId = gr.findIntById(id, ConfigData.MILESTONE_TABLE, "createdBy");
		m.setCreator((Person) gr.findObjectById(createdId , ConfigData.PERSON_TABLE, "obj"));
		
		String deliverableIds = (String) gr.findObjectById(id, ConfigData.MILESTONE_TABLE, "deliverable_ids");
		System.out.println(deliverableIds);
		m.setDeliverableIds(deliverableIds);
		
		m.setProject(m.deliverables.get(0).getProject());
		
		return m;
	}
	
	// Find the latest milestone 
	public static Milestone findLatest() throws SQLException, IOException, NotFoundException, ClassNotFoundException {
		GetRow gr = new GetRow();
		ArrayList<Object>  set = gr.findObjectsByLatest(1,"id DESC", ConfigData.MILESTONE_TABLE ,"obj");
		Milestone m = (Milestone) set.get(0);
		
		int createdId = gr.findIntById(m.id, ConfigData.MILESTONE_TABLE, "createdBy");
		m.setCreator((Person) gr.findObjectById(createdId , ConfigData.PERSON_TABLE, "obj"));
		
		String deliverableIds = (String) gr.findObjectById(m.id, ConfigData.MILESTONE_TABLE, "deliverableIds");
		m.setDeliverableIds(deliverableIds);
		
		m.setProject(m.deliverables.get(0).getProject());
		
		return m;
	}
	

	@Override
	protected String getTableName() {
		return ConfigData.MILESTONE_TABLE;
	}

	@Override
	public void setId(int id) {
		this.id = id;
		
	}
	public void setId(String id)
	{
		setId(Integer.parseInt(id));
	}
	public void setNumber(String num)
	{
		setMilestoneNumber(Integer.parseInt(num));
	}
	public void setDateAchieved(String date) {
		SimpleDateFormat d = new SimpleDateFormat("MM/dd/yy");
		try {
			this.completionDate = d.parse(date);
		} catch (ParseException e) {
		}

	}
	public void setDateProjected(String date) {
		SimpleDateFormat d = new SimpleDateFormat("MM/dd/yy");
		try {
			this.projectedCompletion = d.parse(date);
		} catch (ParseException e) {
		}

	}
	public void setDeliverableIds(String deliverableIds)
	{
		if (deliverableIds == null || deliverableIds.equalsIgnoreCase(""))
			return;
		List<Deliverable> deliverables = new ArrayList<Deliverable>();
        String[] splitArray = deliverableIds.split("\\,");
        for (String id: splitArray) {
        	try {
        		Deliverable p = Deliverable.find(Integer.parseInt(id));
				deliverables.add(p);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
        this.deliverables = (ArrayList<Deliverable>) deliverables;
	}

	public static Milestone fromExcel(ExcelConnector ec, int rowNumber) throws Exception {
		//@TODO: move to config
		ec.setWorksheet(WORKSHEET_NAME);
		List<Field> fields = ec.getRow(rowNumber);
		Milestone m = new Milestone();
		return (Milestone) Reflector.setReflectedMethods(fields, m, Class.forName("models.Milestone"));		
	}


}

